
package MuleBackend;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import javax.swing.*;

import com.google.gson.Gson;

import MuleGUI.*;

/**
 * the game class represents the mule game
 * contains the logic for and pieces for playing
 * a game of mule
 * @author Jackson
 *
 */
public class Game {
	int mapNum, numPlayers, rounds, roundNumber;
	String difficulty, currentStage;
	ArrayList<Player> playerList;
	ArrayList<ImageIcon> imageList;
	Board board;
	Player currentPlayer;
	Stages stages;
	Town town;
	transient public BoardGUI boardGUI;
	transient StatusGUI statusGUI;
	transient LandAuctionGUI landAuctionGUI;
	transient GoodAuctionGUI auctionGUI;
	transient GameOverGUI gameOverGUI;
	transient public TownGUI townGUI;
	
	public static Game instance = null;

	/**
	 * constructor for the game class
	 * holds all the pieces of the game
	 * @param args
	 */
	public Game() {
		numPlayers = 0;
		difficulty = "";
		mapNum = 0;
		rounds = 0;
		roundNumber= 0;
		currentPlayer = null;
		currentStage = "";
		playerList = new ArrayList<Player>();
		imageList = new ArrayList<ImageIcon>();
		board = new Board();
		town = new Town();
				
		statusGUI = new StatusGUI();
		landAuctionGUI = new LandAuctionGUI();
		auctionGUI = new GoodAuctionGUI();
		gameOverGUI = new GameOverGUI();
		townGUI = new TownGUI();
		boardGUI = new BoardGUI();
		stages = new Stages();
	}
	
	/**
	 * setter method to set the board (used in loading)
	 * @param newboard board to instantiate
	 */
	public void setBoard(Board newboard) {
		board = newboard;
	}
	/**
	 * getter method to get the town
	 * @return the town
	 */
	public Town getTown() {
		return town;
	}

	/**
	 * getter method to get the townGUI
	 * @return the townGUI object
	 */
	public TownGUI getTownGUI(){
		return townGUI;
	}
	
	/**
	 * method to save the game
	 */
	public void saveGame() {
		final Gson gson = new Gson();
		
		Game game1 = getInstance();
		
		String json = gson.toJson(game1);
		PrintWriter out = null;
		try {
			out = new PrintWriter(new FileOutputStream("SaveData.txt"));
			out.print(json);
		} catch (IOException e) {
			//empty
		}
		finally {
			if (out != null) out.close();
		}
		System.out.println("game saved");
	}
	
	/**
	 * This will update all the information panels
	 * of all the players
	 */
	public void updateInfoPanels() { 
		boardGUI.updateInfoPanels(); 
	}
	
	/**
	 * gets the round number the game is currently on
	 * @return the round number the game is on
	 */
	public int getRoundNumber() {
		return roundNumber; 
	}
	
	/**
	 * setter to set the round number (used in loading)
	 * @param num the number to set the rounds to
	 */
	public void setRoundNumber(int num) {
		roundNumber = num; 
	}
	
	/**
	 * sets the current stage to a string representation
	 * @param theStage the stage the game is currently on
	 */
	public void setCurrentStage(String theStage) {
		currentStage = theStage; 
	}
	
	/**
	 * gets the current stage in a string form
	 * @return the current stage
	 */
	public String getCurrentStage() {
		return currentStage; 
	}
	
	/**
	 * setter method to set the current player
	 * @param num the current player
	 */
	public void setCurrentPlayer(Player player) {
		currentPlayer = player; 
	
	}
	
	/**
	 * getter method to get the current player
	 * @return the current player taking their turn
	 */
	public Player getCurrentPlayer(){
		return currentPlayer;
	}
	
	
	
	/**
	 * getter method to get the current player
	 * @return the current player taking their turn
	 */
	public Player getActivePlayer() { 
		Player p = null;
		for (Player player : playerList) {
			if (currentPlayer == player) {
				p = player;
			}
		}
		return p; 
	}
	
	/**
	 * method to return the board
	 * @return a 2d array that contains the lands
	 */
	public Land[][] getLandsArray() {
		return board.getLandsArray(); 
	}
	
	/**
	 * method to get the stages
	 * @return the stages object of the game
	 */
	public Stages getStages() {
		return stages; 
	}
	
	/**
	 * setter method to set the stages (used in loading)
	 * @param thestage the stages to instantiate
	 */
	public void setStages(Stages thestage) { 
		stages = thestage;
	}
	
	/**
	 * method to show the storeGUI (when you enter town)
	 */
	public void showTownGUI(int x, int y){
		townGUI.setVisible(true);
		townGUI.startPlayer(x,y);
	}
	
	/**
	 * method to show the storeGUI (when you enter town)
	 */
	public void showTownGUI() {
		townGUI.setVisible(true); 
	}
	
	/**
	 * method to hide the storeGUI (when you leave town)
	 */
	public void hideTownGUI() {
		townGUI.dispose(); 
	}

	/**
	 * method to add players into game's player arraylist
	 * used in nameGUI when initializing players
	 * @param player the player created from nameGUI
	 */
	public void addPlayer(Player player) {
		playerList.add(player); 
	}
	
	/**
	 * helper method for the loading functionality
	 * @param image image to add to the list
	 */
	public void addImages(ImageIcon image) {
		imageList.add(image); 
	}
	
	/**
	 * getter method to return the image list
	 * @return imagelist of the game
	 */
	public ArrayList<ImageIcon> getImageList() {
		return imageList;
	}

	/**
	 * method to generate the map depending on
	 * input from startGUI (tile placements)
	 * @param num the number of the map you are using
	 */
	public void generateMap(int num) {
		board.createMap(num); 
	}

	/**
	 * sets the number of rounds in the game
	 * determined by startGUI
	 * @param num the number of rounds
	 */
	public void setRounds(int num) {
		rounds = num; 
	}
	
	/**
	 * getter method to get the rounds (used in loading)
	 * @return the round number
	 */
	public int getRounds() {
		return rounds; 
	}

	/**
	 * sets the map number variable for the game object
	 * for System.out.println purposes
	 * @param num the number of the map
	 */
	public void setMapNum(int num) {
		mapNum = num; 
	}

	/**
	 * getter method to get the map number (used in loading)
	 * @return mapNum
	 */
	public int getMapNum() {
		return mapNum;
	}
	
	/**
	 * sets the difficulty variable for the game object
	 * for System.out.println purposes
	 * @param string
	 */
	public void setDifficulty(String string) {
		difficulty = string; 
	}

	/**
	 * sets the number of players variable for the game object
	 * for System.out.println purposes
	 * @param num
	 */
	public void setNumPlayers(int num) {
		numPlayers = num; 
	}

	/**
	 * creates a single game object if it hasn't been made yet
	 * @return the game object
	 */
	public static Game getInstance() {
		if (instance == null) {
			instance = new Game(); 
		}
		return instance;
	}

	/**
	 * method to return the players in the game
	 * @return a list of all the players
	 */
	public ArrayList<Player> getPlayerList() {
		return playerList; 
	}

	/**
	 * prints out various variables in the game object
	 * for testing purposes
	 */
	public String toString() {
		return "Game Difficulty :" + difficulty + "\n" +
				"Game Map Type :" + mapNum + "\n" +
				"Game Number Of Players :" + numPlayers+ "\n" +
				"Total Rounds :" + rounds + "\n" +
				"Game round number :" + roundNumber +"\n" + 
				"Current Stage : " + currentStage;
	}

	/**
	 * stage cycling method
	 * @param i
	 */
	public void startStage()
	{		
		if (++roundNumber<= rounds)
		{
			stages.startStage(1);
			stages.setPlayerList();
		}
	}
	
	
	/**
	 * method that will draw the map and
	 * add the right action listeners
	 */
	public void createMap() {
		getBoardGUI().addMap();
	}
	
	/**
	 * This method is primarily used with the PubListener in StoreGUI.
	 * 
	 * The getTurnPercentRemaining() method accesses the progress bar on the right hand
	 * side of the board and returns the percentage of the bar remaining at the time of 
	 * the method's call.
	 *
	 *@author Phil
	 *
	 */
	
	/**
	 * gets the remaining percentage of time from the jprogressbar
	 * @return the percent remaining from boardGUI's jprogressbar
	 */
	public double getTurnPercentRemaining()
	{
		return boardGUI.getJProgressBar().getPercentComplete();
	}
	
	/**
	 * getter method to get the JProgressBar of the boardGUI
	 * @return
	 */
	public JProgressBar getJProgressBar() {
		return boardGUI.getJProgressBar();
	}
	
	/**
	 * gets the difficulty of the game
	 * @return the difficulty of the game
	 */
	public String getDifficulty() {
		return difficulty; 
	}
	
	/**
	 * gets the timer of the game
	 * @return the timer of the gaem
	 */
	public Timer getTimer() {
		return stages.getTimer(); 
	}

	/**
	 * method to tell the stages to end the timer
	 */
	public void endTimer() {
		stages.endTimer();
	}
	
	/**
	 * getter method to get the boardGUI
	 * @return the boardGUI
	 */
	public BoardGUI getBoardGUI() {
		return boardGUI; 
	}
	
	/**
	 * method to show the boardGUI (when you enter town)
	 */
	public void showBoardGUI(){
		boardGUI.setVisible(true);
	}
	
	/**
	 * Getter for board
	 * @return board the game board
	 */
	public Board getBoard() {
		return board; 
	}

	/**
	 * gets the number of the players in the game
	 * @return the total number of active players
	 */
	public int getNumPlayers() {
		return playerList.size();
	}
}	//end of game class
